//-----------------------------------------------------------------------
// <copyright file="DefaultSubscriptionSelectorPolicy.cs" company="iron9light">
//      Copyright (c) iron9light. All rights reserved.
// </copyright>
// <author>iron9light</author>
//-----------------------------------------------------------------------

namespace EventBrokerExtension
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Reflection;

    using Microsoft.Practices.ObjectBuilder2;

    /// <summary>
    /// An implementation of <see cref="ISubscriptionSelectorPolicy"/> that is aware of
    /// the build keys used by the unity container.
    /// </summary>
    public class DefaultSubscriptionSelectorPolicy : ISubscriptionSelectorPolicy
    {
        /// <summary>
        /// Return the sequence of subscription informations.
        /// </summary>
        /// <param name="context">Current build context.</param>
        /// <returns>Sequence of subscription informations.</returns>
        public IEnumerable<SubscriptionInfo> GetSubscriptionInfos(IBuilderContext context)
        {
            Type t = BuildKey.GetType(context.BuildKey);

            foreach (MethodInfo method in t.GetMethods(BindingFlags.Instance | BindingFlags.Public))
            {
                if (method.IsDefined(typeof(SubscribesToAttribute), true) && !method.IsGenericMethodDefinition && IsValidParameters(method.GetParameters()))
                {
                    foreach (SubscriptionInfo subscriptionInfo in CreateSubscriptionInfos(method))
                    {
                        yield return subscriptionInfo;
                    }
                }
            }
        }

        private static bool IsValidParameters(ParameterInfo[] parameters)
        {
            return parameters.Length == 2 && typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType);
        }

        private static IEnumerable<SubscriptionInfo> CreateSubscriptionInfos(MethodInfo methodInfo)
        {
            List<SubscribesToAttribute> attributes =
                    new List<SubscribesToAttribute>(
                            Sequence.OfType<SubscribesToAttribute>(
                                    methodInfo.GetCustomAttributes(typeof(SubscribesToAttribute), true)));

            Debug.Assert(attributes.Count == 1, "We must have one of these, otherwise this method would never have been called.");

            foreach (SubscribesToAttribute attribute in attributes)
            {
                yield return new SubscriptionInfo(attribute.EventTopic, methodInfo);
            }
        }
    }
}